/*
 * FreeModbus Libary: STM32 Port
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: portserial_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
 */

#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"


#define hdlrs485USARTx USART2
#define hdlrs485USART_CLK_CMD RCC_APB1PeriphClockCmd
#define hdlrs485USART_CLK RCC_APB1Periph_USART2
#define hdlrs485USART_IRQ USART2_IRQn
#define hdlrs485USART_IRQHANDLER USART2_IRQHandler

#define hdlrs485USART_GPIO_TX_CLK RCC_AHB1Periph_GPIOA
#define hdlrs485USART_GPIO_TX_PORT GPIOA
#define hdlrs485USART_GPIO_TX_PIN GPIO_Pin_2
#define hdlrs485USART_GPIO_TX_PIN_SRC GPIO_PinSource2

#define hdlrs485UASRT_GPIO_RX_CLK RCC_AHB1Periph_GPIOA
#define hdlrs485USART_GPIO_RX_PORT GPIOA
#define hdlrs485USART_GPIO_RX_PIN GPIO_Pin_3
#define hdlrs485USART_GPIO_RX_PIN_SRC GPIO_PinSource3

#define hdlrs485USART_AF GPIO_AF_USART2

#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
/* ----------------------- Start implementation -----------------------------*/

void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
    if (xRxEnable) {
        //		MASTER_RS485_RECEIVE_MODE;
        USART_ITConfig(hdlrs485USARTx, USART_IT_RXNE, ENABLE);
    }
    else {
        //		MASTER_RS485_SEND_MODE;
        USART_ITConfig(hdlrs485USARTx, USART_IT_RXNE, DISABLE);
    }
    if (xTxEnable) {
        USART_ITConfig(hdlrs485USARTx, USART_IT_TXE, ENABLE);
    }
    else {
        USART_ITConfig(hdlrs485USARTx, USART_IT_TXE, DISABLE);
    }
}

void vMBMasterPortClose(void)
{
    USART_ITConfig(hdlrs485USARTx, USART_IT_TXE | USART_IT_RXNE, DISABLE);
    USART_Cmd(hdlrs485USARTx, DISABLE);
}
// 默认一个主机 串口2 波特率可设置  奇偶检验可设置
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity)
{
    GPIO_InitTypeDef  uxrs485_pin_struct;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;


    RCC_AHB1PeriphClockCmd(hdlrs485USART_GPIO_TX_CLK, ENABLE);   // 使能GPIOA时钟
    RCC_AHB1PeriphClockCmd(hdlrs485UASRT_GPIO_RX_CLK, ENABLE);   // 使能GPIOA时钟
    hdlrs485USART_CLK_CMD(hdlrs485USART_CLK, ENABLE);            // 使能USART2时钟

    // 串口2引脚复用映射
    GPIO_PinAFConfig(hdlrs485USART_GPIO_TX_PORT,
                     hdlrs485USART_GPIO_TX_PIN_SRC,
                     hdlrs485USART_AF);   // GPIOA2复用为USART2
    GPIO_PinAFConfig(hdlrs485USART_GPIO_RX_PORT,
                     hdlrs485USART_GPIO_RX_PIN_SRC,
                     hdlrs485USART_AF);   // GPIOA3复用为USART2


    uxrs485_pin_struct.GPIO_Mode  = GPIO_Mode_AF;
    uxrs485_pin_struct.GPIO_OType = GPIO_OType_PP;
    uxrs485_pin_struct.GPIO_PuPd  = GPIO_PuPd_UP;
    uxrs485_pin_struct.GPIO_Speed = GPIO_Speed_100MHz;

    uxrs485_pin_struct.GPIO_Pin = hdlrs485USART_GPIO_TX_PIN;
    GPIO_Init(hdlrs485USART_GPIO_TX_PORT, &uxrs485_pin_struct);   // 初始化PA2，PA3

    uxrs485_pin_struct.GPIO_Pin = hdlrs485USART_GPIO_RX_PIN;
    GPIO_Init(hdlrs485USART_GPIO_RX_PORT, &uxrs485_pin_struct);   // 初始化PA2，PA3



    //======================串口初始化=======================================
    USART_InitStructure.USART_BaudRate = ulBaudRate;
    // 设置校验模式

    USART_InitStructure.USART_Parity     = USART_Parity_No;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 一个停止位
    USART_InitStructure.USART_Parity   = USART_Parity_No;    // 无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl =
        USART_HardwareFlowControl_None;                               // 无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 收发模式

    ENTER_CRITICAL_SECTION();   // 关全局中断

    USART_Init(hdlrs485USARTx, &USART_InitStructure);

    USART_ITConfig(hdlrs485USARTx, USART_IT_RXNE, ENABLE);   // 开启接受中断

    USART_ClearFlag(hdlrs485USARTx, USART_FLAG_TC);

    USART_Cmd(hdlrs485USARTx, ENABLE);   // 使能串口 2

    //=====================中断初始化======================================
    // 设置NVIC优先级分组为Group2：0-3抢占式优先级，0-3的响应式优先级
    NVIC_InitStructure.NVIC_IRQChannel                   = hdlrs485USART_IRQ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    EXIT_CRITICAL_SECTION();   // 开全局中断

    return TRUE;
}

BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{
    USART_SendData(hdlrs485USARTx, ucByte);
    while (USART_GetFlagStatus(hdlrs485USARTx, USART_FLAG_TXE) == 0);   // 等待发送完成
    return TRUE;
}

BOOL xMBMasterPortSerialGetByte(CHAR* pucByte)
{
    *pucByte =
        (uint8_t)(USART_ReceiveData(hdlrs485USARTx) & (uint8_t)0x00FF);   // 获取接收BUFFER的数据
    return TRUE;
}

/*
 * Create an interrupt handler for the transmit buffer empty interrupt
 * (or an equivalent) for your target processor. This function should then
 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
 * a new character can be sent. The protocol stack will then call
 * xMBPortSerialPutByte( ) to send the character.
 */
void prvvUARTTxReadyISR(void)
{
    pxMBMasterFrameCBTransmitterEmpty();
}

/*
 * Create an interrupt handler for the receive interrupt for your target
 * processor. This function should then call pxMBFrameCBByteReceived( ). The
 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
 * character.
 */
void prvvUARTRxISR(void)
{
    pxMBMasterFrameCBByteReceived();
}
/*******************************************************************************
 * Function Name  : USART2_IRQHandler
 * Description    : This function handles USART2 global interrupt request.
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void hdlrs485USART_IRQHANDLER(void)
{
    //	rt_interrupt_enter();

    if (USART_GetITStatus(hdlrs485USARTx, USART_IT_TXE) &&
        (USART_GetFlagStatus(hdlrs485USARTx, USART_FLAG_TC))) {
        prvvUARTTxReadyISR();
        USART_ClearITPendingBit(hdlrs485USARTx, USART_IT_TXE);
    }
    else if (USART_GetITStatus(hdlrs485USARTx, USART_IT_RXNE))   // 接收中断
    {
        prvvUARTRxISR();   // pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
        USART_ClearITPendingBit(hdlrs485USARTx, USART_IT_RXNE);
    }


    //	rt_interrupt_leave();
}

#endif
